`include "PRV564Config.v"
`include "PRV564Define.v"
//////////////////////////////////////////////////////////////////////////////////////////////////
//  Date    : 2021                                                                              //
//  Author  : yinchengbin                                                                       //
//  Desc    : ALU core for PRV564 processor                                                     //
//  Version : 1.0		                                                                        //
//////////////////////////////////////////////////////////////////////////////////////////////////
module ALUcore(
//----------------------Input-------------------------------
    input wire              Valid,              //if opcode is valid, if valid=0 all the opcode is treated as NOP
    input wire [7:0]        Opcode,             //opcode
    input wire [1:0]        OpInfo,             //op information
    input wire [`XLEN-1:0]  DataSource1,        
    input wire [`XLEN-1:0]  DataSource2,
//----------------------Output-------------------------------
    output  [`XLEN-1:0]  DataOut1,
    output  [`XLEN-1:0]  DataOut2
);


//
//--------------------------------Opcode decode------------------------------
//
wire [3:0] Opcode_valid ;								//Opcode的低四位；对于ALU的基本操作，只有低四位有效，高四位为0
assign Opcode_valid = {4{Valid}} & Opcode[3:0];			//门控，避免不必要的晶体管翻转

wire op_ALU_NOP;  
wire op_ALU_JAL;  
wire op_ALU_CSRW;
wire op_ALU_CSRS;
wire op_ALU_CSRC; 
wire op_ALU_ADD;  
wire op_ALU_SUB;  
wire op_ALU_SLT;  
wire op_ALU_XOR;  
wire op_ALU_OR;   
wire op_ALU_AND;  
wire op_ALU_SL;   
wire op_ALU_SR;

assign op_ALU_NOP  = (Opcode_valid == 4'h0 || Valid == 1'b0) ? 1'b1 : 1'b0;
assign op_ALU_JAL  = (Opcode_valid == 4'h3) ? 1'b1 : 1'b0;
assign op_ALU_CSRW = (Opcode_valid == 4'h4) ? 1'b1 : 1'b0;
assign op_ALU_CSRS = (Opcode_valid == 4'h5) ? 1'b1 : 1'b0;
assign op_ALU_CSRC = (Opcode_valid == 4'h6) ? 1'b1 : 1'b0;
assign op_ALU_ADD  = (Opcode_valid == 4'h8) ? 1'b1 : 1'b0;
assign op_ALU_SUB  = (Opcode_valid == 4'hF) ? 1'b1 : 1'b0;
assign op_ALU_SLT  = (Opcode_valid == 4'h9) ? 1'b1 : 1'b0;
assign op_ALU_XOR  = (Opcode_valid == 4'hA) ? 1'b1 : 1'b0;
assign op_ALU_OR   = (Opcode_valid == 4'hB) ? 1'b1 : 1'b0;
assign op_ALU_AND  = (Opcode_valid == 4'hC) ? 1'b1 : 1'b0;
assign op_ALU_SL   = (Opcode_valid == 4'hD) ? 1'b1 : 1'b0;
assign op_ALU_SR   = (Opcode_valid == 4'hE) ? 1'b1 : 1'b0;

//
//----------------------------------------data path-------------------------------------------
//


wire [`XLEN-1:0] data_ALU_NOP_1  ,data_ALU_NOP_2;
wire [`XLEN-1:0] data_ALU_JAL_1  ,data_ALU_JAL_2;
wire [`XLEN-1:0] data_ALU_CSRW_1 ,data_ALU_CSRW_2;
wire [`XLEN-1:0] data_ALU_CSRS_1 ,data_ALU_CSRS_2;
wire [`XLEN-1:0] data_ALU_CSRC_1 ,data_ALU_CSRC_2;
wire [`XLEN-1:0] data_ALU_ADD;
wire [`XLEN-1:0] data_ALU_SUB;
wire [`XLEN-1:0] data_ALU_SLT;
wire [`XLEN-1:0] data_ALU_XOR;
wire [`XLEN-1:0] data_ALU_OR;
wire [`XLEN-1:0] data_ALU_AND;
wire [`XLEN-1:0] data_ALU_SL;
wire [`XLEN-1:0] data_ALU_SR;

//---------------------------------算数加减法中间值--------------------------------------
wire [`XLEN-1:0] add_sub_result_tem;					//进行64bits的加减法的的临时结果
wire [`XLEN-1:0] add_64_tem;
wire [`XLEN-1:0] sub_64_tem;

//-----------------------------------NOP------------------------------------------------------------------
assign data_ALU_NOP_1 = DataSource1;
assign data_ALU_NOP_2 = DataSource2;

//-----------------------------------JAL----------------------------------------------------------------------
assign data_ALU_JAL_1 = op_ALU_JAL ? (DataSource1 + 4) 	: {`XLEN{1'b0}};
assign data_ALU_JAL_2 = op_ALU_JAL ? DataSource2 		: {`XLEN{1'b0}};

//-----------------------------------CSRW----------------------------------------------------------------------
assign data_ALU_CSRW_1 = op_ALU_CSRW ? DataSource2 : {`XLEN{1'b0}};
assign data_ALU_CSRW_2 = op_ALU_CSRW ? DataSource1 : {`XLEN{1'b0}};

//------------------------------------CSRS----------------------------------------------------------------------
assign data_ALU_CSRS_1 = op_ALU_CSRS ? DataSource2 					: {`XLEN{1'b0}};
assign data_ALU_CSRS_2 = op_ALU_CSRS ? (DataSource2 | DataSource1) 	: {`XLEN{1'b0}};

//------------------------------------CSRC----------------------------------------------------------------------
assign data_ALU_CSRC_1 = op_ALU_CSRC ? DataSource2 						: {`XLEN{1'b0}};
assign data_ALU_CSRC_2 = op_ALU_CSRC ? (DataSource2 &( ~DataSource1)) 	: {`XLEN{1'b0}};

//----------------------------------ADD & SUB----------------------------------------------------------------------
assign add_sub_result_tem = (op_ALU_ADD | op_ALU_SUB) ? (DataSource1 + (op_ALU_SUB ? (~DataSource2) : DataSource2)) :  {`XLEN{1'b0}};
assign add_64_tem = add_sub_result_tem;
assign sub_64_tem = add_sub_result_tem + 1'b1;

assign data_ALU_ADD[63:32]= (OpInfo[1] ? {32{add_64_tem[31]}} : add_64_tem[63:32]);
assign data_ALU_ADD[31:0] =  add_64_tem[31:0];

assign data_ALU_SUB[63:32]= (OpInfo[1] ? {32{sub_64_tem[31]}} : sub_64_tem[63:32]);
assign data_ALU_SUB[31:0] =  sub_64_tem[31:0];

//-------------------------------------SLT---------------------------------------------------------------------
assign data_ALU_SLT = op_ALU_SLT ? 																					//门控信号
						(((~OpInfo[0]&((~DataSource2[63] & DataSource1[63]) | 										//sign64
								(DataSource2[63] && DataSource1[63] && DataSource2 > DataSource1) |
								(!DataSource2[63] && !DataSource1[63] && DataSource2 > DataSource1)))|
					    (OpInfo[0] & DataSource2 > DataSource1)) ? 64'd1: {`XLEN{1'b0}}) : {`XLEN{1'b0}};			//Unsign64

//------------------------------------XOR---------------------------------------------------------------------
assign data_ALU_XOR = op_ALU_XOR ? (DataSource1 ^ DataSource2) : {`XLEN{1'b0}};

//------------------------------------OR-----------------------------------------------------------------------
assign data_ALU_OR = op_ALU_OR ? (DataSource1 | DataSource2) : {`XLEN{1'b0}};

//------------------------------------AND-----------------------------------------------------------------------
assign data_ALU_AND = op_ALU_AND ? (DataSource1 & DataSource2) : {`XLEN{1'b0}};

//----------------------------------SL & SR--------------------------------------------------------------------
//参考的桶形移位器设计
//shiftnum为6bits，桶形移位器共有六级，由于存在有符号数和无符号数，64bits和32bits的存在，导致每一级的组合逻辑过于复杂，
//本设计将数据流根据有无符号位和数据位宽拆分为4个并行的通路,在增大面积的同时，一定程度上缩短了延时，
//若时序仍紧张，可以考虑将左移和右移动继续拆分
//
wire [5:0] shiftnum;
wire [31:0]shift0_32;
wire [31:0]shift0_u32;
wire [63:0]shift0_64;
wire [63:0]shift0_u64;
wire [31:0]shift1_32;
wire [31:0]shift1_u32;
wire [63:0]shift1_64;
wire [63:0]shift1_u64;
wire [31:0]shift2_32;
wire [31:0]shift2_u32;
wire [63:0]shift2_64;
wire [63:0]shift2_u64;
wire [31:0]shift3_32;
wire [31:0]shift3_u32;
wire [63:0]shift3_64;
wire [63:0]shift3_u64;
wire [31:0]shift4_32;
wire [31:0]shift4_u32;
wire [63:0]shift4_64;
wire [63:0]shift4_u64;
wire [63:0]shift5_32;
wire [63:0]shift5_u32;
wire [63:0]shift5_64;
wire [63:0]shift5_u64;

assign shiftnum = DataSource2[5:0];

//--------------------------------32位有符号数----------------------------------------------
assign shift0_32= (OpInfo == 2'b10) ?
				(shiftnum[0]?
				(op_ALU_SR ? {DataSource1[31],DataSource1[31:1]}:			//右移
				{DataSource1[30:0],1'd0}): 									//左移
				DataSource1[31:0])											//不移动
				: {32{1'b0}};											//数据通路未开启
assign shift1_32= shiftnum[1]?
				(op_ALU_SR ? {{2{shift0_32[31]}},shift0_32[31:2]}:			//右移
				{shift0_32[29:0],2'd0}): 									//左移
				shift0_32;													//不移动
assign shift2_32= shiftnum[2]?
				(op_ALU_SR ? {{4{shift1_32[31]}},shift1_32[31:4]}:			//右移
				{shift1_32[27:0],4'd0}): 									//左移
				shift1_32;													//不移动		
assign shift3_32= shiftnum[3]?
				(op_ALU_SR ? {{8{shift2_32[31]}},shift2_32[31:8]}:			//右移
				{shift2_32[23:0],8'd0}): 									//左移
				shift2_32;													//不移动	
assign shift4_32= shiftnum[4]?
				(op_ALU_SR ? {{16{shift3_32[31]}},shift3_32[31:16]}:		//右移
				{shift3_32[15:0],16'd0}): 									//左移
				shift3_32;													//不移动	
assign shift5_32= {{32{shift4_32[31]}},shift4_32};							//符号位拓展

//---------------------------------32位无符号数----------------------------------------------
assign shift0_u32= (OpInfo == 2'b11) ?
				(shiftnum[0]?
				(op_ALU_SR ? {1'd0,DataSource1[31:1]}:						//右移
				{DataSource1[30:0],1'd0}): 									//左移
				{DataSource1[31:0]})										//不移动
				: {32{1'b0}};											//数据通路未开启
assign shift1_u32= shiftnum[1]?
				(op_ALU_SR ? {2'd0,shift0_u32[31:2]}:						//右移
				{shift0_u32[29:0],2'd0}): 									//左移
				shift0_u32;													//不移动
assign shift2_u32= shiftnum[2]?
				(op_ALU_SR ? {4'd0,shift1_u32[31:4]}:						//右移
				{shift1_u32[27:0],4'd0}): 									//左移
				shift1_u32;													//不移动		
assign shift3_u32= shiftnum[3]?
				(op_ALU_SR ? {8'd0,shift2_u32[31:8]}:						//右移
				{shift2_u32[23:0],8'd0}): 									//左移
				shift2_u32;													//不移动	
assign shift4_u32= shiftnum[4]?
				(op_ALU_SR ? {16'd0,shift3_u32[31:16]}:						//右移
				{shift3_u32[15:0],16'd0}): 									//左移
				shift3_u32;													//不移动			
assign shift5_u32= {{32{shift4_u32[31]}},shift4_u32}; 						//符号位拓展


//----------------------------------64位有符号数----------------------------------------------
assign shift0_64= (OpInfo == 2'b00) ?
				(shiftnum[0]?
				(op_ALU_SR ? {{2{DataSource1[63]}},DataSource1[62:1]}:			//右移
				{DataSource1[62:0],1'd0}): 										//左移
				DataSource1)													//不移动
				: {`XLEN{1'b0}};												//数据通路未开启
assign shift1_64= shiftnum[1]?
				(op_ALU_SR ? {{3{shift0_64[63]}},shift0_64[62:2]}:				//右移
				{shift0_64[61:0],2'd0}): 										//左移
				shift0_64;														//不移动
assign shift2_64= shiftnum[2]?
				(op_ALU_SR ? {{5{shift1_64[63]}},shift1_64[62:4]}:				//右移
				{shift1_64[59:0],4'd0}): 										//左移
				shift1_64;														//不移动		
assign shift3_64= shiftnum[3]?
				(op_ALU_SR ? {{9{shift2_64[63]}},shift2_64[62:8]}:				//右移
				{shift2_64[55:0],8'd0}): 										//左移
				shift2_64;														//不移动	
assign shift4_64= shiftnum[4]?
				(op_ALU_SR ? {{17{shift3_64[63]}},shift3_64[62:16]}:			//右移
				{shift3_64[47:0],16'd0}): 										//左移
				shift3_64;														//不移动
assign shift5_64= shiftnum[5]?
				(op_ALU_SR ? {{33{shift4_64[63]}},shift4_64[62:32]}:			//右移
				{shift4_64[31:0],32'd0}): 										//左移
				shift4_64;			

//------------------------------------64位无符号数----------------------------------------------
assign shift0_u64= (OpInfo == 2'b01) ?
				(shiftnum[0]?
				(op_ALU_SR ? {1'd0,DataSource1[63:1]}:				//右移
				{DataSource1[62:0],1'd0}): 							//左移
				DataSource1)										//不移不移动
				: {`XLEN{1'b0}};									//数据通路未开启
assign shift1_u64= shiftnum[1]?
				(op_ALU_SR ? {2'd0,shift0_u64[63:2]}:				//右移
				{shift0_u64[61:0],2'd0}): 							//左移
				shift0_u64;											//不移动
assign shift2_u64= shiftnum[2]?
				(op_ALU_SR ? {4'd0,shift1_u64[63:4]}:				//右移
				{shift1_u64[59:0],4'd0}): 							//左移
				shift1_u64;											//不移动		
assign shift3_u64= shiftnum[3]?
				(op_ALU_SR ? {8'd0,shift2_u64[63:8]}:				//右移
				{shift2_u64[55:0],8'd0}): 							//左移
				shift2_u64;											//不移动	
assign shift4_u64= shiftnum[4]?
				(op_ALU_SR ? {16'd0,shift3_u64[63:16]}:				//右移
				{shift3_u64[47:0],16'd0}): 							//左移
				shift3_u64;											//不移动	
assign shift5_u64= shiftnum[5]?
				(op_ALU_SR ? {32'd0,shift4_u64[63:32]}:				//右移
				{shift4_u64[31:0],32'd0}): 							//左移
				shift4_u64;	

assign data_ALU_SL = op_ALU_SL ? (shift5_32 | shift5_u32 | shift5_64 |shift5_u64) :{`XLEN{1'b0}};
assign data_ALU_SR = op_ALU_SR ? (shift5_32 | shift5_u32 | shift5_64 |shift5_u64) :{`XLEN{1'b0}};




//   
//------------------------------------Output-------------------------------
//
assign DataOut1 = 	(op_ALU_NOP 	? data_ALU_NOP_1 	: {`XLEN{1'b0}}) |
					(op_ALU_JAL 	? data_ALU_JAL_1 	: {`XLEN{1'b0}}) |
					(op_ALU_CSRW 	? data_ALU_CSRW_1 	: {`XLEN{1'b0}}) |
					(op_ALU_CSRS 	? data_ALU_CSRS_1 	: {`XLEN{1'b0}}) |
					(op_ALU_CSRC 	? data_ALU_CSRC_1 	: {`XLEN{1'b0}}) |
					(op_ALU_ADD 	? data_ALU_ADD 		: {`XLEN{1'b0}}) |
					(op_ALU_SUB 	? data_ALU_SUB 		: {`XLEN{1'b0}}) |
					(op_ALU_SLT 	? data_ALU_SLT 		: {`XLEN{1'b0}}) |
					(op_ALU_XOR 	? data_ALU_XOR 		: {`XLEN{1'b0}}) |
					(op_ALU_OR 		? data_ALU_OR 		: {`XLEN{1'b0}}) |
					(op_ALU_AND 	? data_ALU_AND 		: {`XLEN{1'b0}}) |
					(op_ALU_SL 		? data_ALU_SL 		: {`XLEN{1'b0}}) |
					(op_ALU_SR 		? data_ALU_SR 		: {`XLEN{1'b0}}) | 64'd0;

assign DataOut2 = 	(op_ALU_NOP 	? data_ALU_NOP_2 	: {`XLEN{1'b0}}) |
					(op_ALU_JAL 	? data_ALU_JAL_2 	: {`XLEN{1'b0}}) |
					(op_ALU_CSRW 	? data_ALU_CSRW_2 	: {`XLEN{1'b0}}) |
					(op_ALU_CSRS 	? data_ALU_CSRS_2 	: {`XLEN{1'b0}}) |
					(op_ALU_CSRC 	? data_ALU_CSRC_2 	: {`XLEN{1'b0}}) | 64'd0;





endmodule
